package cn.sys.util;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * 解析request请求中的数据，将其封装到指定的实体类中
 */
public class ParseRequestParameterUtilTest {

    /** 用来解析request中的请求数据。请求数据的格式即为Map<String, String[]>类型的。
     * @param params    请求数据
     * @param aClass    要封装的对象的类型
     * @return  存好数据的object对象
     */
    public static Object parseRequestParam(Map<String, String[]> params, Class aClass){
        Object obj = null;
        try {
            obj = aClass.getConstructor().newInstance();
            Field[] fields = aClass.getFields();
            Set<String> keys = params.keySet();
            // 1. 通过自定义的方法，找出map和类中所对应的属性的Field对象，并将对应得上的存储在map中
            Map<String, Field> fieldNameMappingField = getExistField(fields, keys);
            Set<String> fieldNames = fieldNameMappingField.keySet();
            for (String fieldName : fieldNames) {
                // 根据属性名生成对应的set方法
                String setMethodName = concatSetMethodName(fieldName);
                // set方法的类型和属性的类型是一致的
                Field field = fieldNameMappingField.get(fieldName);
                Method setMethod = aClass.getMethod(setMethodName, field.getType());

                // 2. 执行方法之前，需要判断该值是否是String[]类型，（如果提交了复选框，就是这个值，需要把它）。
                String[] strings = params.get(fieldName);
                // 调用set方法进行赋值
                runSetMethod(setMethod, field, strings, obj);
            }
        }catch (Exception e){
            e.getStackTrace();
        }
        return obj;
    }

    /**
     * 从前端拿到数据后，封装给obj对象
     * @param method
     * @param field
     * @param strings
     * @param obj
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    private static void runSetMethod(Method method, Field field, String[] strings, Object obj) throws InvocationTargetException, IllegalAccessException, ParseException {
        // 注意1：有提交的数据没有值的情况，此时就不做处理，对象中有默认值
        if(strings.length == 1) {
            // 注意2：拿到的属性都是String类型的，但实际赋值的可能是其他数据类型：Integer、Double、Date、Boolean、String（常见的基本就这些）。
            if(field.getType().equals(Integer.class) || field.getType().equals(int.class)){
                    if(strings[0] != null && !"".equals(strings[0])){
                    Integer value = Integer.parseInt(strings[0]);
                    method.invoke(obj, value);
                }
            }else if(field.getType().equals(Byte.class) || field.getType().equals(byte.class)){
                if(strings[0] != null && !"".equals(strings[0])){
                    Byte value = Byte.parseByte(strings[0]);
                    method.invoke(obj, value);
                }
            }else if(field.getType().equals(Short.class) || field.getType().equals(short.class)){
                if(strings[0] != null && !"".equals(strings[0])){
                    Short value = Short.parseShort(strings[0]);
                    method.invoke(obj, value);
                }
            }else if(field.getType().equals(Long.class) || field.getType().equals(long.class)){
                if(strings[0] != null && !"".equals(strings[0])){
                    Long value = Long.parseLong(strings[0]);
                    method.invoke(obj, value);
                }
            }else if(field.getType().equals(Double.class) || field.getType().equals(double.class)){
                if(strings[0] != null && !"".equals(strings[0])){
                    Double value = Double.parseDouble(strings[0]);
                    method.invoke(obj, value);
                }
            }else if(field.getType().equals(Float.class) || field.getType().equals(float.class)){
                if(strings[0] != null && !"".equals(strings[0])){
                    Float value = Float.parseFloat(strings[0]);
                    method.invoke(obj, value);
                }
            }else if(field.getType().equals(Boolean.class) || field.getType().equals(boolean.class)){
                if(strings[0] != null && !"".equals(strings[0])){
                    Boolean value = Boolean.parseBoolean(strings[0]);
                    method.invoke(obj, value);
                }
            }else if(field.getType().equals(Date.class)){
                SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm");
                if(strings[0] != null && !"".equals(strings[0])){
                    Date value = format.parse(strings[0]);
                    method.invoke(obj, value);
                }
            }else { // 字符类型
                method.invoke(obj, strings[0]);
            }
        }else{
            /*
                如果strings中有多个数据，属性类型可能是数组，也可能是集合，
                需要确定数组或集合中的泛型的数据类型。
             */
            /*if(field.getType().isArray()){  // 数组
                //field.getGenericType().getTypeName();
            }else { // 集合

            }
            if(field.getType().equals(Integer.class) || field.getType().equals(int.class)){
                if(strings[0] != null && !"".equals(strings[0])){
                    Integer value = Integer.parseInt(strings[0]);
                    method.invoke(obj, value);
                }
            }else { // 字符类型
                method.invoke(obj, strings[0]);
            }*/
        }
    }

    // 判断属性是否在类中存在，如果存在返回具体的Field对象，否则返回空
    private static Field existField(Field[] fields, String key){
        for (int i = 0; i < fields.length; i++) {
            if(fields[i].getName().equals(key)){
                return fields[i];
            }
        }
        return null;
    }

    /**
     * 建立起所有的key和value的对应关系，存储到Map中，方便以后使用
     * @param fields    类中所有的属性
     * @param keys  Map中所有的key
     * @return
     */
    private static Map<String, Field> getExistField(Field[] fields, Set<String> keys){
        // 存储Map中的key和属性Field之间的映射管理
        Map<String, Field> keyMappingField = new HashMap<>();
        // 遍历keys
        for (String key : keys) {
            // 判断key是否是类的属性，如果是，还要拿到该属性
            Field field = existField(fields, key);
            if(field != null){
                keyMappingField.put(key, field);
            }
        }
        return keyMappingField;
    }

    // 根据属性名拼接set方法名
    private static String concatSetMethodName(String fieldName){
        char[] chars = fieldName.toCharArray();
        chars[0] =(char)(chars[0] - 32);
        fieldName = new String(chars);
        return "set" + fieldName;
    }
}
